package pacman;

import java.util.ArrayList;
import java.lang.Math;
import java.util.Random;

/**
 * This class implements a yellow ghost, who hunts the nearest pacman, but only if he can see him (i.e. they are on the same row or line, and there is no "unaccessible" case for the ghost.
 * Keeps the same direction as long as possible and if he doesn't see another pacman on his way. Otherwise moves randomly.
 */
public class cYellowGhost implements iGhost {
    Position intended = new Position(0, 0);
    Position lastPos;
    Position pos;
    cCore parent;
    Random rand = new Random();
    
    /**
     * Creates a new instance of cYellowGhost.
     * @param parent The core where the ghost is to be created.
     * @param position The initial position of the ghost.
     */
    public cYellowGhost(cCore parent, Position position) {
        pos = position;
        lastPos = pos;
        this.parent = parent;
    }

    /**
     * Makes the ghost to move.
     */
    public void Move() {
        cPacman pac = null;
        int visibility = Math.max(parent.getPlateau().length, parent.getPlateau()[0].length);
        int tempVisibility;
        
        for(int i = 0; i < parent.getPacmanList().size(); i++) {
            cPacman temp = parent.getPacmanList().get(i);
            
            //Selects the nearest visible pacman
            if(!temp.IsDead()) {
                tempVisibility = visible(temp);
                if(tempVisibility > 0 && tempVisibility < visibility) {
                    visibility = tempVisibility;
                    pac = temp;
                    if(sameLine(pac)) {
                        intended = new Position(Math.abs(pac.getPosition().getX()-this.pos.getX())/(pac.getPosition().getX()-this.pos.getX()), 0);
                    }
                    else {
                        intended = new Position(0, Math.abs(pac.getPosition().getY()-this.pos.getY())/(pac.getPosition().getY()-this.pos.getY()));
                    }
                }
            }
        }
        
        if(parent.isAccessible(new Position(this.getPosition().getX() + intended.getX(), this.getPosition().getY() + intended.getY()), this) && !intended.equals(new Position(0, 0))) {
            lastPos = pos;
            pos = pos.clone();
            pos.incX(intended.getX());
            pos.incY(intended.getY());
        }
        
        else {
            intended = new Position(0, 0);
            lastPos = pos;
            pos = randomPos();
        }
    }

    /**
     * Returns the current position of the ghost.
     * @return The current position of the ghost.
     */
    public Position getPosition() {
        return pos;
    }
    
    /**
     * Returns the name of the image to be loaded for this ghost.
     * @return A string containing the name of the image to be loaded for this ghost.
     */
    public String getImageName() {
        return "yellowghost";
    }
    
    private boolean sameLine(cPacman pac) {
        if(this.pos.getY() == pac.getPosition().getY()) {
            return true;
        }
        return false;
    }
    
    private boolean sameRow(cPacman pac) {
        if(this.pos.getX() == pac.getPosition().getX()) {
            return true;
        }
        return false;
    }
    
    private int visible(cPacman pac) {
        Position temp;
        int delta = 0;
        int dist = 0;
        if (sameLine(pac)) {
            dist = pac.getPosition().getX()-this.getPosition().getX();
            delta = Math.abs(dist)/dist;
            
            for(int i = 0; i <= Math.abs(dist); i++) {
                temp = this.pos.clone();
                temp.incX(i*delta);
                if(!parent.isAccessible(temp, this)) {
                    return -1;
                }
            }
            return Math.abs(dist);
        }
        if (sameRow(pac)) {
            dist = pac.getPosition().getY()-this.getPosition().getY();
            delta = Math.abs(dist)/dist;
            
            for(int i = 0; i <= Math.abs(dist); i++) {
                temp = this.pos.clone();
                temp.incY(i*delta);
                if(!parent.isAccessible(temp, this)) {
                    return -1;
                }
            }
            return Math.abs(dist);
        }
        return -1;
    }
    
    private Position randomPos() {
        ArrayList<Position> nextPos = new ArrayList<Position>();
        Position tmp = this.pos.clone();
        
        //Tests all positions around current one to see if it's usable
        tmp.incX(1);
        if(parent.isAccessible(tmp,this) && !tmp.equals(lastPos)) {
            nextPos.add(tmp.clone());
        }
        tmp.incX(-2);
        if(parent.isAccessible(tmp,this) && !tmp.equals(lastPos)) {
            nextPos.add(tmp.clone());
        }
        tmp.incX(1);
        tmp.incY(1);
        if(parent.isAccessible(tmp,this) && !tmp.equals(lastPos)) {
            nextPos.add(tmp.clone());
        }
        tmp.incY(-2);
        if(parent.isAccessible(tmp,this) && !tmp.equals(lastPos)) {
            nextPos.add(tmp.clone());
        }
        
        if(nextPos.size()<1) {
            nextPos.add(lastPos);
        }
        
        return nextPos.get(rand.nextInt(nextPos.size()));
    }
}
